package com.youxin.foundation.db.redis;


import org.apache.log4j.Logger;

import redis.clients.jedis.JedisCommands;

/**
 * Redis分布式锁的实现
 * 
 * @author yingde.cao
 *
 */
public class RedisDistributedLock<T extends JedisCommands>   {
	private static Logger logger = Logger.getLogger(RedisDistributedLock.class);
	private T redisCommand;

	public RedisDistributedLock(T redisCommand) {
		this.redisCommand = redisCommand;
	}

	/**
	 * redis锁
	 * @param key redis的key
	 * @param timeoutMillis 超时时间
	 * @param commandable 命令接口
	 */
	public  void lock(String key, long timeoutMillis, JedisCommandsable<T> commandable)
	{		
		if (timeoutMillis <=1000) {
			timeoutMillis=10000;
			//throw new RuntimeException("RedisDistributedLock lock的timeoutMillis为" + timeoutMillis + ",超时时间不能小于0.");
		}
		long timeValue = System.currentTimeMillis() + timeoutMillis;
		String timeValueString=String.valueOf(timeValue);
		int expiresSecond = 60;
		Long result = redisCommand.setnx(key, timeValueString);
		if (new Long(1).equals(result)) {			
			/**
			 * 设置临时键超时时间
			 */
			redisCommand.setex(key, expiresSecond, String.valueOf(timeValue));
			commandable.execute(redisCommand);
			
			timeValue = System.currentTimeMillis() + timeoutMillis;
			/**
			 * 重新设置时间,如果时间没有被其它线程修改,就删除当前键.
			 */
			String oldValue = redisCommand.getSet(key, String.valueOf(timeValue));
			if(timeValueString.equals(oldValue))
			{
				redisCommand.del(key);
			}
		} else {
			String value = redisCommand.get(key);
			if(value==null)
			{
				logger.warn("key:"+key+"的值为:"+String.valueOf(value)+",setnx:"+timeValueString+"的值为:"+String.valueOf(result));
				return ;
			}
			timeValue = Long.valueOf(value);
			/**
			 * 获取保存的时间判断是否超时,如果超时,就重新设置当前值,并获取结果,比较获取到的结果和原先的值,如果值一样,就表示获取到当前锁
			 */
			if (value!=null&timeValue < System.currentTimeMillis()) {
				
				timeValue = System.currentTimeMillis() + timeoutMillis;
				String oldValue = redisCommand.getSet(key, String.valueOf(timeValue));
				
				if (value.equals(oldValue)) {
					redisCommand.setex(key, expiresSecond, String.valueOf(timeValue));
					commandable.execute(redisCommand);
					redisCommand.del(key);
				}
			}
		}
	}
	
	private void checkValue(JedisCommandsable<T> commandable,String key,String tempKey)
	{
		
	}

}
